#include "dunHeap.h"


t_heap 	heapCreate(size_t size)
{
	t_heap result = calloc(1, sizeof (struct s_heap));
	result->som = calloc((size + 1), sizeof (int));
	result->dist = calloc((size + 1), sizeof (float));
	result->pos = calloc((size + 1), sizeof (int));
	result->life = calloc(1, (size + 1) * sizeof (int));
	result->size_max = size;
	return (result);
}

void	heapAdd(t_heap *h, int som, int life, float dist)
{
	size_t i;
	t_heap t = *h;
	i = t->size++ + 1;
	t->som[i] = som;
	t->dist[i] = dist;
	t->life[i] = life;
	t->pos[som] = i;
	heapPercolateUp(h, i);
}

void	heapExtractMin(t_heap *h, int* outsom, int* outlife)
{
	t_heap t = *h;
	int i;
	if (!t->size)
		return;
	*outsom = t->som[1];
	*outlife = t->dist[1];
	t->pos[*outsom] = 0;
	i = t->size--;
	t->som[1] = t->som[i];
	t->dist[1] = t->dist[i];
	t->life[1] = t->life[i];
	if (t->size)
		t->pos[t->som[1]] = 1;
	heapPercolateDown(h, 1);
}

void	heapUpdate(t_heap *h, int som, int life, float dist)
{
	t_heap t = *h;
	size_t i = t->pos[som];
	if (!i)
		heapAdd(h, som, life, dist);
	else
	{
		t->life[i] = life;
		if (dist < t->dist[i])
		{
			t->dist[i] = dist;
			heapPercolateUp(h, i);
		}
		else
		{
			t->dist[i] = dist;
			heapPercolateDown(h, i);
		}
	}
}

void	heapPercolateDown(t_heap *h, size_t i)
{
	t_heap t = *h;
	int x, y;
	size_t l = LEFT(i), r = RIGHT(i), m;
	while ((r <= t->size) 
		&& ((t->dist[i] > t->dist[l]) 
			|| (t->dist[i] > t->dist[r])))
	{
		m = (t->dist[l] < t->dist[r]) ? l : r;
		x = t->som[i];
		y = t->som[m];
		swapFloat(&t->dist[i], &t->dist[m]);
		swapInt(&t->som[i], &t->som[m]);
		swapInt(&t->life[i], &t->life[m]);
		swapInt(&t->pos[x], &t->pos[y]);
		i = m;
		l = LEFT(i);
		r = RIGHT(i);
	}
}

void	heapPercolateUp(t_heap *h, size_t i)
{
	t_heap t = *h;
	int x, y;
	size_t parent = PARENT(i);
	while ((i > 0) && (t->dist[i] < t->dist[parent]))
	{
		x = t->som[i];
		y = t->som[parent];
		swapInt(&t->som[i], &t->som[parent]);
		swapInt(&t->life[i], &t->life[parent]);
		swapFloat(&t->dist[i], &t->dist[parent]);
		swapInt(&t->pos[x], &t->pos[y]);
		i = parent;
		parent = PARENT(i);
	}
}


void heapPrint(t_heap h)
{
	size_t i;

	for (i = 1; i <= h->size; i++)
	{
		printf("[%lu]: som: %d | life: %d | dist: %f | pos: %d\n", i, h->som[i], h->life[i], h->dist[i], h->pos[h->som[i]]);
	}
	printf("size: %lu\n", h->size);
}


void swapInt(int* a, int* b)
{
	int c;
	c = *a;
	*a = *b;
	*b = c;
}

void swapFloat(float* a, float* b)
{
	float c;
	c = *a;
	*a = *b;
	*b = c;
}

void heapResize(t_heap *h, size_t size)
{
	*h = realloc(*h, (*h)->size_max + size);
}

void	heapFree(t_heap t)
{
	free(t->som);
	free(t->dist);
	free(t->pos);
	free(t->life);

	free(t);
}